﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows.Controls;
using System.Windows;
using System.Xml;
using System.ComponentModel;
using System.Windows.Documents;
using System.Diagnostics;

using InfFront.InfoViews.Base;

namespace InfFront.InfoViews.WPF
{
    public class HyperTextBlock: TextBlock
    {
        #region Private fields

        private static DependencyProperty hyperTextProperty;
        
        #endregion Private fields

        #region Construction/Initalization

        static HyperTextBlock()
        {
            var metaData = new PropertyMetadata(new PropertyChangedCallback(onHyperTextChanged));
            hyperTextProperty = DependencyProperty.Register("HyperText", typeof(string), typeof(HyperTextBlock), metaData);
        }

        #endregion Construction/Initalization

        /// <summary>
        /// Gets or sets the simple hyper text xml. You may use <b>, <i>, <u>, <br/> and <a> tags here
        /// </summary>
        [Category("Common Properties"), DefaultValue(null), Description("Gets or sets the simple hyper text xml. You may use <b>, <i>, <u>, <br/> and <a> tags here")]
        public RawString HyperText
        {
            get { return (RawString)GetValue(hyperTextProperty); }
            set { SetValue(hyperTextProperty, value); }
        }

        #region Private members

        private static void onHyperTextChanged(DependencyObject obj, DependencyPropertyChangedEventArgs args)
        {
            var self = (HyperTextBlock) obj;
            var doc = new XmlDocument();
            var str = (string)args.NewValue;
            doc.InnerXml = string.Format("<Root>{0}</Root>", str);
            self.Rebuild((XmlElement)doc.FirstChild);
        }

        private void Rebuild(XmlElement root)
        {
            Inlines.Clear();
            if (root == null || root.FirstChild == null)
                return;
            foreach (XmlNode node in root.ChildNodes)
                ProcessNode(Inlines, node);
        }

        private void ProcessNode(InlineCollection inlines, XmlNode node)
        {
            if (node is XmlText)
            {
                inlines.Add(node.InnerText);
                return;
            }

            var asElem = node as XmlElement;
            if (asElem != null)
            {
                Span curSpan = null;
                switch (asElem.Name.ToUpper())
                {
                    case "B":
                    case "BOLD":
                        curSpan = new Bold();
                        break;
                    case "I":
                    case "ITALIC":
                        curSpan = new Italic();
                        break;
                    case "U":
                    case "UNDERLINE":
                        curSpan = new Underline();
                        break;
                    case "A":
                    case "LINK":
                    case "HYPERLINK":
                        var hl = new Hyperlink();
                        var attrs = asElem.Attributes;
                        var hrefAttr = attrs.GetNamedItem("href");
                        if (hrefAttr == null)
                            hrefAttr = attrs.GetNamedItem("url");
                        if (hrefAttr != null)
                        {
                            hl.NavigateUri = new Uri(hrefAttr.InnerText);
                            hl.RequestNavigate += new System.Windows.Navigation.RequestNavigateEventHandler(hyperLink_RequestNavigate);
                        }
                        curSpan = hl;
                        break;
                    case "BR":
                    case "LINEBREAK":
                        inlines.Add(new LineBreak());
                        return;
                    default:
                        throw new NotSupportedException(string.Format("Unknown format tag: '<{0}>'. You may use only <b>, <i>, <u>, <br/> or <a>", asElem.Name));
                }

                inlines.Add(curSpan);
                foreach (XmlNode childNode in asElem.ChildNodes)
                {
                    if (!(childNode is XmlAttribute))
                        ProcessNode(curSpan.Inlines, childNode);
                }
                return;
            }

            Debug.Assert(false);
            throw new NotSupportedException(string.Format("Unknown XmlNode: {0}", node));
        }

        void hyperLink_RequestNavigate(object sender, System.Windows.Navigation.RequestNavigateEventArgs e)
        {
            Hyperlink thisLink = (Hyperlink)sender;
            string navigateUri = thisLink.NavigateUri.ToString();
            Process.Start(new ProcessStartInfo(navigateUri));
            e.Handled = true;
        }

        #endregion Private members
    }
}
